package com.canaan.business.controller.pc.bill;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import com.canaan.business.common.enums.inOutStock.BillBindOperationEnum;
import com.canaan.business.common.enums.inOutStock.ErpBillTypeEnum;
import com.canaan.business.common.enums.inOutStock.InOrderStatusEnum;
import com.canaan.business.domain.bill.*;
import com.canaan.business.service.bill.*;
import com.canaan.common.encrypt.PushEdiService;
import com.canaan.business.domain.vo.*;
import com.canaan.common.annotation.Log;
import com.canaan.common.core.controller.BaseController;
import com.canaan.common.core.domain.AjaxResult;
import com.canaan.common.core.page.TableDataInfo;
import com.canaan.common.enums.BusinessType;
import com.canaan.common.exception.ServiceException;
import com.canaan.common.utils.DateUtils;
import com.canaan.common.utils.poi.ExcelUtil;
import com.canaan.system.service.ISysConfigService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * 收货单Controller
 *
 * @author ruoyi
 * @date 2023-02-01
 */
@Api(tags = "收货单")
@RestController
@RequestMapping("/bill/receive")
public class ReceiveProductBillController extends BaseController {
    @Resource
    private IReceiveProductBillService receiveProductBillService;

    @Resource
    private IReceiveProductBillDetailService receiveProductBillDetailService;

    @Resource
    private IBillDetailRecordService billDetailRecordService;

    @Resource
    private ITrayService trayService;
    @Resource
    private ITrayDetailService trayDetailService;
    @Resource
    private IAdjustInBillService adjustInBillService;
    @Resource
    private ISysConfigService sysConfigService;
    /**
     * 查询收货单列表
     */
    @ApiOperation(value = "查询收货单列表")
    @GetMapping("/list")
    public TableDataInfo list(ReceiveProductBill receiveProductBill) {
        startPage();
        List<ReceiveProductBill> list = receiveProductBillService.selectReceiveProductBillList(receiveProductBill);
        return getDataTable(list);
    }

    /**
     * 导出到货清单列表
     */
    @ApiOperation(value = "导出到货清单列表")
    @Log(title = "到货清单", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, ReceiveProductBill receiveProductBill) {
        List<ReceiveProductBillExportVo> list = receiveProductBillService.exportList(receiveProductBill);
        ExcelUtil<ReceiveProductBillExportVo> util = new ExcelUtil<>(ReceiveProductBillExportVo.class);
        util.exportExcel(response, list, "收货单数据");
    }

    /**
     * 导出收货单清单列表
     */
    @ApiOperation(value = "导出收货单清单列表")
    @Log(title = "收货单清单", businessType = BusinessType.EXPORT)
    @PostMapping("/exportCheck")
    public void exportCheck(HttpServletResponse response, ReceiveProductBill receiveProductBill) {
        List<ReceiveProductBillExportCheckVo> list = receiveProductBillService.exportCheckList(receiveProductBill);
        ExcelUtil<ReceiveProductBillExportCheckVo> util = new ExcelUtil<>(ReceiveProductBillExportCheckVo.class);
        util.exportExcel(response, list, "收货单清单数据");
    }

    /**
     * 获取收货单详细信息
     */
    @ApiOperation(value = "获取收货单详细信息")
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") Long id) {
        return success(receiveProductBillService.selectReceiveProductBillById(id));
    }

    /**
     * 新增收货单
     */
    @ApiOperation(value = "新增收货单")
    @Log(title = "收货单", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody ReceiveProductBill receiveProductBill) {
        return toAjax(receiveProductBillService.insertReceiveProductBill(receiveProductBill));
    }

    /**
     * 修改收货单
     */
    @ApiOperation(value = "修改收货单")
    @Log(title = "收货单", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody ReceiveProductBill receiveProductBill) {
        return toAjax(receiveProductBillService.updateReceiveProductBill(receiveProductBill));
    }

    /**
     * 删除收货单
     */
    @ApiOperation(value = "删除收货单")
    @Log(title = "收货单", businessType = BusinessType.DELETE)
	@DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable Long[] ids) {
        return toAjax(receiveProductBillService.deleteReceiveProductBillByIds(ids));
    }

    /**
     * 导入到货单
     */
    @ApiOperation(value = "导入到货单")
    @PostMapping("/importExcel")
    @Log(title = "导入到货单", businessType = BusinessType.IMPORT)
    public AjaxResult importExcel(MultipartFile file) {
        List<ReceiveProductBillExportVo> list;
        try {
            //读取excel文件数据
            ExcelUtil<ReceiveProductBillExportVo> util = new ExcelUtil<>(ReceiveProductBillExportVo.class);
            list = util.importExcel(file.getInputStream());
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException("导入文件解析失败");
        }
        //初步校验数据
        if (CollectionUtils.isEmpty(list)) {
            throw new ServiceException("文件缺少数据");
        }
        //深入校验数据和保存数据
        try {
            List<String> errorList = receiveProductBillService.importExcel(list);
            if (!errorList.isEmpty()) {
                StringBuilder failureMsg = new StringBuilder();
                failureMsg.append("很抱歉，导入失败！共 ").append(errorList.size()).append(" 条数据格式不正确，错误如下：");
                for (int i = 0; i < errorList.size(); i++) {
                    failureMsg.append("<br/>").append(i + 1).append("、").append(errorList.get(i));
                }
                return error(failureMsg.toString());
            }
            return success("导入成功");
        }catch (Exception ex){
             ex.printStackTrace();;
            return error ("导入失败");
        }
    }


    /**
     * 到货单导入模板
     */
    @ApiOperation(value = "到货单导入模板")
    @PostMapping("/importTemplate")
    public void importTemplate(HttpServletResponse response) {
        ExcelUtil<ReceiveProductBillExportVo> util = new ExcelUtil<>(ReceiveProductBillExportVo.class);
        util.importTemplateExcel(response, "收货单导入模板");
    }

    /**
     * 收货单导入模板
     */
    @ApiOperation(value = "收货单导入模板")
    @PostMapping("/importTemplateCheck")
    public void importTemplateCheck(HttpServletResponse response) {
        ExcelUtil<ReceiveProductBillExportCheckVo> util = new ExcelUtil<>(ReceiveProductBillExportCheckVo.class);
        util.importTemplateExcel(response, "收货单导入模板");
    }

    @ApiOperation(value = "完成收货")
    @Log(title = "完成收货", businessType = BusinessType.UPDATE)
    @PostMapping("/complete")
    public AjaxResult complete(@RequestBody ReceiveProductBill receiveProductBill){
        ReceiveProductBill bill=receiveProductBillService.selectReceiveProductBillByNo(receiveProductBill.getNo());
        if(bill==null){
            return error("采购入库单"+receiveProductBill.getNo()+"不存在");
        }
        if (StrUtil.equals(bill.getShortMatch(), "0") && Long.compare(bill.getTotalQty(), receiveProductBill.getTotalQty()) > 0) {
            //不支持短收
            return error("采购入库单" + receiveProductBill.getNo() + "不支持短收");
        }
        bill.setStatus(InOrderStatusEnum.ACCOMPLISH.getCode());
        bill.setCompleteTime(DateUtils.getNowDate());
        //上报给ERP
        if(bill!=null){
            adjustInBillService.postInStockCallback(bill.getNo(),bill.getStockStatus());
        }
        int result = receiveProductBillService.updateReceiveProductBill(bill);
        return toAjax(result);
    }

    /**
     * 确定
     */
    @ApiOperation(value = "确定")
    @Log(title = "确定", businessType = BusinessType.UPDATE)
    @PostMapping("/confirm")
    public AjaxResult confirm(@RequestBody ReceiveProductBill bill){
        if(bill == null || bill.getId() == null){
            throw new ServiceException("缺少必要参数");
        }
        int result=receiveProductBillService.confirm(bill);

        return toAjax(result);
    }
    /**
     * 入库回调
     * @param bill 采购入库单
     */
    private void postInstockCallback(ReceiveProductBill bill){
        InStockCallbackVo inStockCallbackVo = new InStockCallbackVo();
        inStockCallbackVo.setBizNo(bill.getNo());
        inStockCallbackVo.setWmsBizNo(bill.getNo());
        ReceiveProductBillDetail query=new ReceiveProductBillDetail();
        query.setBillNo(bill.getNo());
        List<ReceiveProductBillDetail> details=receiveProductBillDetailService.selectReceiveProductBillDetailList(query);
        List<GoodsVo> goodsVos=new ArrayList<>();
        for (ReceiveProductBillDetail item : details){
            GoodsVo goodsVo=new GoodsVo();
            goodsVo.setBatchNo(item.getBatchNo());
            goodsVo.setCode(item.getProductNo());
            goodsVo.setUnit(item.getProductUnit());
            goodsVo.setNum(item.getReceivedQty().toString());
            goodsVo.setStatus(Integer.parseInt(bill.getStockStatus()));
            goodsVos.add(goodsVo);
        }
        inStockCallbackVo.setGoodDetails(goodsVos);
        SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        inStockCallbackVo.setDeliveryDate(simpleDateFormat.format(DateUtils.getNowDate()));
        // 发送回调
        if(Boolean.parseBoolean(sysConfigService.selectConfigByKey("edi.swtich"))){
            Pair<Boolean, String> result= PushEdiService.push(sysConfigService.selectConfigByKey("edi.inner"), JSONUtil.toJsonStr(inStockCallbackVo));
            System.out.println("post = " + result.getValue());
            if(!result.getKey()){
                throw new RuntimeException(result.getValue());
            }
        }
    }
    /**
     * 收货
     */
    @ApiOperation(value = "收货")
    @Log(title = "收货", businessType = BusinessType.UPDATE)
    @PostMapping("/addDetail")
    @Transactional
    public AjaxResult addDetail(@RequestBody ReceiveProductDetailVo detailVo){
        if(detailVo.getProductDate()==null){
            return error("生产日期不能为空");
        }
        int result=addReceiveProductDetail(detailVo)?1:0;
        return toAjax(result);
    }

    /**
     * 添加收货明细
     * @param detailVo 收货明细
     * @return
     */
    private boolean addReceiveProductDetail(ReceiveProductDetailVo detailVo){
        //更新明细数量
        ReceiveProductBillDetail query=new ReceiveProductBillDetail();
        query.setBillNo(detailVo.getBillNo());
        query.setProductNo(detailVo.getProductNo());
        query.setDelFlag("0");

        ReceiveProductBill receiveProductBill=receiveProductBillService.selectReceiveProductBillByNo(detailVo.getBillNo());
        if (receiveProductBill==null){
            throw new RuntimeException("采购入库单"+detailVo.getBillNo()+"不存在");
        }
        if(detailVo.getQty() <=0){
            throw new RuntimeException("采购入库单"+detailVo.getBillNo()+"收货数量必须大于0");
        }
        if(receiveProductBill.getCheckTotalQty()+detailVo.getQty()>receiveProductBill.getTotalQty()){
            throw new RuntimeException("采购入库单"+detailVo.getBillNo()+"收货总数超过"+receiveProductBill.getTotalQty());
        }
        TrayDetail trDetail = new TrayDetail();
        trDetail.setTrayNo(detailVo.getTrayNo());
        List<TrayDetail> trayDetails =  trayDetailService.selectTrayDetailList(trDetail);
        if (CollectionUtil.isNotEmpty(trayDetails)) {
            //一个托盘只能放一种物料和一个批次
            throw new RuntimeException("托盘" + detailVo.getTrayNo() + "已经存在物料" + trayDetails.get(0).getProductNo());
        }
        receiveProductBill.setCheckTotalQty(receiveProductBill.getCheckTotalQty()+detailVo.getQty());
        receiveProductBill.setStatus(InOrderStatusEnum.PICKING.getCode());
        receiveProductBillService.updateReceiveProductBill(receiveProductBill);

        List<ReceiveProductBillDetail> receiveProductBillDetails=receiveProductBillDetailService.selectReceiveProductBillDetailList(query);
        if(receiveProductBillDetails==null||receiveProductBillDetails.size()==0){
            throw new RuntimeException(detailVo.getBillNo()+"不存在物料"+detailVo.getProductNo()+"明细");
        }
        ReceiveProductBillDetail receiveProductBillDetail=receiveProductBillDetails.get(0);
        if(receiveProductBillDetail.getReceivedQty()+detailVo.getQty()>receiveProductBillDetail.getQty()){
            throw new RuntimeException(detailVo.getBillNo()+"不存在物料"+detailVo.getProductNo()+"明细超出数量"+receiveProductBillDetail.getQty());
        }


        //增加单据明细
        BillDetailRecord billDetailRecord=new BillDetailRecord();
        billDetailRecord.setBillNo(detailVo.getBillNo());
        billDetailRecord.setTrayNo(detailVo.getTrayNo());
        billDetailRecord.setBillType(ErpBillTypeEnum.RECEIVE_PRODUCT.getCode());
        billDetailRecord.setProductNo(detailVo.getProductNo());
        billDetailRecord.setProductName(detailVo.getProductName());
        billDetailRecord.setBatchNo(detailVo.getBatchNo());
        billDetailRecord.setQty(detailVo.getQty());
        billDetailRecord.setProductUnit(detailVo.getProductUnit());
        billDetailRecord.setOperation(BillBindOperationEnum.RECEIVE_PRODUCT.getMessage());
        billDetailRecord.setStockStatus(receiveProductBill.getStockStatus());
        billDetailRecord.setProductionDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,detailVo.getProductDate()));
        billDetailRecord.setExpiryDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,detailVo.getValidDate()));
        billDetailRecordService.insertBillDetailRecord(billDetailRecord);
        //修改对应的明细表批次号,返回给EDI时需要用到
        receiveProductBillDetail.setProductDate(detailVo.getProductDate());
        receiveProductBillDetail.setValidDate(detailVo.getValidDate());
        receiveProductBillDetail.setReceivedQty(receiveProductBillDetail.getReceivedQty()+detailVo.getQty());
        receiveProductBillDetail.setBatchNo(detailVo.getBatchNo());
        receiveProductBillDetailService.updateReceiveProductBillDetail(receiveProductBillDetail);
        //增加托盘
        Tray tray=trayService.selectTrayByTrayNo(detailVo.getTrayNo());
        if(tray==null){
            tray=new Tray();
            tray.setErpInBillNo(receiveProductBill.getNo());
            tray.setStockStatus(receiveProductBill.getStockStatus());
            tray.setTrayNo(detailVo.getTrayNo());
            tray.setOwner(receiveProductBill.getOwner());
            tray.setStockCode(receiveProductBill.getStockCode());
            trayService.insertTray(tray);
        }
        else{
            tray.setErpInBillNo(receiveProductBill.getNo());
            tray.setStockStatus(receiveProductBill.getStockStatus());
            tray.setErpOutBillNo("");
            tray.setSplitBillNo("");
            tray.setOutBillNo("");
            tray.setInBillNo("");
            tray.setOwner(receiveProductBill.getOwner());
            tray.setStockCode(receiveProductBill.getStockCode());
            trayService.updateTray(tray);
        }
        //增加托盘明细
        TrayDetail trayDetailQuery=new TrayDetail();
        trayDetailQuery.setTrayNo(detailVo.getTrayNo());
        trayDetailQuery.setProductNo(detailVo.getProductNo());
        trayDetailQuery.setDelFlag("0");
        trayDetailQuery.setBatchNo(detailVo.getBatchNo());
        List<TrayDetail> trayResults=trayDetailService.selectTrayDetailList(trayDetailQuery);
        if(trayResults!=null&&trayResults.size()!=0){
            throw new RuntimeException("托盘"+detailVo.getTrayNo()+"已经存在物料"+detailVo.getProductNo()+"明细");
        }
        TrayDetail trayDetail =new TrayDetail();
        trayDetail.setTrayNo(detailVo.getTrayNo());
        trayDetail.setProductName(detailVo.getProductName());
        trayDetail.setProductNo(detailVo.getProductNo());
        trayDetail.setProductUnit(detailVo.getProductUnit());
        trayDetail.setBatchNo(detailVo.getBatchNo());
        trayDetail.setStockStatus(receiveProductBill.getStockStatus());
        trayDetail.setQty(detailVo.getQty());
        trayDetail.setProductionDate(detailVo.getProductDate());
        if(detailVo.getProductDate()!=null&&detailVo.getValidDate()!=null) {
            trayDetail.setValidDateNum(DateUtils.differentDaysByMillisecond(detailVo.getValidDate(), detailVo.getProductDate()));
        }
        trayDetailService.insertTrayDetail(trayDetail);
        return  true;
    }
    /**
     * 确定
     */
    @ApiOperation(value = "删除明细")
    @Log(title = "删除明细", businessType = BusinessType.UPDATE)
    @PostMapping("/deleteDetail")
    public AjaxResult deleteDetail(@RequestBody ReceiveProductDetailVo detailVo){
        int result=deleteReceiveProductDetail(detailVo)?1:0;
        return toAjax(result);
    }

    /**
     * 删除明细
     * @param detailVo
     * @return
     */
    @Transactional
    public boolean deleteReceiveProductDetail(ReceiveProductDetailVo detailVo){
        //更新明细数量
        ReceiveProductBillDetail query=new ReceiveProductBillDetail();
        query.setBillNo(detailVo.getBillNo());
        query.setProductNo(detailVo.getProductNo());
        query.setDelFlag("0");

        ReceiveProductBill receiveProductBill=receiveProductBillService.selectReceiveProductBillByNo(detailVo.getBillNo());
        if (receiveProductBill==null){
            throw new RuntimeException("采购入库单"+detailVo.getBillNo()+"不存在");
        }
        if(receiveProductBill.getCheckTotalQty()-detailVo.getQty()<0){
            receiveProductBill.setCheckTotalQty(0l);
        }
        else {
            receiveProductBill.setCheckTotalQty(receiveProductBill.getCheckTotalQty() - detailVo.getQty());
        }
        receiveProductBillService.updateReceiveProductBill(receiveProductBill);

        List<ReceiveProductBillDetail> receiveProductBillDetails=receiveProductBillDetailService.selectReceiveProductBillDetailList(query);
        if(receiveProductBillDetails==null||receiveProductBillDetails.size()==0){
            throw new RuntimeException("采购入库单"+detailVo.getBillNo()+"不存在物料"+detailVo.getProductNo()+"明细");
        }
        ReceiveProductBillDetail receiveProductBillDetail=receiveProductBillDetails.get(0);
        if(receiveProductBillDetail.getReceivedQty()-detailVo.getQty()<0){
            receiveProductBillDetail.setReceivedQty(0l);
        }
        else{
            receiveProductBillDetail.setReceivedQty(receiveProductBillDetail.getReceivedQty()-detailVo.getQty());
        }
        receiveProductBillDetailService.updateReceiveProductBillDetail(receiveProductBillDetail);
        //增加单据明细
        BillDetailRecord billDetailQuery=new BillDetailRecord();
        billDetailQuery.setBillNo(detailVo.getBillNo());
        billDetailQuery.setTrayNo(detailVo.getTrayNo());
        billDetailQuery.setProductNo(detailVo.getProductNo());
        billDetailQuery.setDelFlag("0");
        List<BillDetailRecord> billDetailRecords=billDetailRecordService.selectBillDetailRecordList(billDetailQuery);
        if(billDetailRecords==null||billDetailRecords.size()==0){
            throw new RuntimeException(detailVo.getBillNo()+"单据明细中不存在托盘"+detailVo.getTrayNo()+"物料"+detailVo.getProductNo());
        }
        BillDetailRecord record=billDetailRecords.get(0);
        billDetailRecordService.deleteBillDetailRecordById(record.getId());
        //增加托盘明细
        TrayDetail trayDetailQuery =new TrayDetail();
        trayDetailQuery.setTrayNo(detailVo.getTrayNo());
        trayDetailQuery.setProductNo(detailVo.getProductNo());
        trayDetailQuery.setDelFlag("0");
        List<TrayDetail> trayDetails=trayDetailService.selectTrayDetailList(trayDetailQuery);
        if(trayDetails==null||trayDetails.size()==0){
            throw new RuntimeException("托盘"+detailVo.getTrayNo()+"明细中不存在物料"+detailVo.getProductNo());
        }
        TrayDetail trayDetail=trayDetails.get(0);
        trayDetailService.deleteTrayDetailById(trayDetail.getId());
        return  true;
    }


    /**
     * 收货单打印
     */
    @ApiOperation(value = "收货单打印")
    @Log(title = "收货单打印", businessType = BusinessType.EXPORT)
    @GetMapping("/selectReceiveBillForPrint")
    public AjaxResult selectReceiveBillForPrint(@RequestParam("no") String no) {
        return success(receiveProductBillService.selectReceiveBillForPrint(no));
    }
}
